#! -*- coding: utf-8 -*-
"""
工具模块
"""
import pickle, struct
from socket import htonl, ntohl


class MessageHeadError(Exception):
    pass

MESSAGE_HEAD_LENGTH = 4	# 消息头的长度为4个字节


def parse_head(head):
    """
    desc:	解析消息头
    param:
        head:   待解析的消息头
    return:
        int:    解析后的消息头
    exception: MessageHeadError, 消息头长度不是指定的长度时, 抛出该异常
    """
    if len(head) != MESSAGE_HEAD_LENGTH:
        raise MessageHeadError("message head length = " + len(head))
    res = struct.unpack('<L', head)[0]  # 从字节解析为整形数字
    res = ntohl(res)    # 避免客户端服务器字节序不一致, 因此在发送和接收时都做了统一的转换
    return res


def parse_body(body):
    """
    desc:	解析消息体
    param:
        head:   待解析的消息体
    return:
        dict:    解析后的消息体
    """
    res = deserialize(body)
    return res


def pack_msg(msg):
    """
    desc:   对待发送的消息进行封装(加消息头, 序列化)
    param:
        msg:    待封装的消息
    return:
        str:    封装后的消息
    """
    sequence_msg = serialize(msg)   # 序列化消息体

    msg_len = len(sequence_msg)
    pack_msg_len = struct.pack('<L', htonl(msg_len))    # 对消息体长度封装成消息头

    res = pack_msg_len + sequence_msg   # 拼接消息头和消息体
    return res


def serialize(data):
    """
    desc:   序列化数据
    param
        data:   待序列化的数据
    return:
        str:    序列化后的数据
    """
    return pickle.dumps(data)


def deserialize(data):
    """
    desc:   反序列化数据
    param
        data:   待反序列化的数据
    return:
        str:    反序列化后的数据
    """
    return pickle.loads(data)
